﻿using System;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using SSG.Tools;

namespace SSG.View
{
    /// <summary>
    /// Allows to write to a GUI backed console / Status bar.
    /// </summary>
    public interface IConsoleAndStatus
    {
        /// <summary>
        /// Status bar available?
        /// </summary>
        /// <returns></returns>
        bool HasStatusBar();

        /// <summary>
        /// Console available?
        /// </summary>
        /// <returns></returns>
        bool HasConsole();

        /// <summary>
        /// Write a status message.
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="severity"></param>
        void WriteStatusMsg(string msg, ConsoleAndStatus.Severity severity = ConsoleAndStatus.Severity.Info);

        /// <summary>
        /// Write a console msg
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="severity"></param>
        void WriteConsoleMsg(string msg, ConsoleAndStatus.Severity severity = ConsoleAndStatus.Severity.Info);

        /// <summary>
        /// Clear the status bar message.
        /// </summary>
        void ClearStatusBar();
    }

    /// <summary>
    /// Provides some base functionality, e.g. time out triggered cleaning the status bar.
    /// </summary>
    public abstract class ConsoleAndStatus : IConsoleAndStatus
    {
        /// <summary>
        /// Severity
        /// </summary>
        public enum Severity
        {
            Info,
            Warning,
            Error
        }

        private bool _cleanUpStatusBarAutomatically = true;

        /// <summary>
        /// Clean up status bar every n seconds.
        /// </summary>
        public static int StatusBarCleanupTimeoutMs = 7500;

        /// <summary>
        /// When was status bar msg last written.
        /// </summary>
        protected DateTime LastStatusBarMessage;

        /// <summary>
        /// Constructor.
        /// </summary>
        protected ConsoleAndStatus()
        {
            this.LastStatusBarMessage = DateTime.Now;
            this.ClearStatusBarAsync();
        }

        /// <summary>
        /// Destructor.
        /// </summary>
        ~ConsoleAndStatus()
        {
            this._cleanUpStatusBarAutomatically = false;
        }

        /// <summary>
        /// Status bar available?
        /// </summary>
        /// <returns></returns>
        public abstract bool HasStatusBar();

        /// <summary>
        /// Console available?
        /// </summary>
        /// <returns></returns>
        public abstract bool HasConsole();

        /// <summary>
        /// Write a status message.
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="severity"></param>
        public abstract void WriteStatusMsg(string msg, Severity severity);

        /// <summary>
        /// Write a console msg
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="severity"></param>
        public abstract void WriteConsoleMsg(string msg, Severity severity);

        /// <summary>
        /// Clear the status bar message.
        /// </summary>
        public abstract void ClearStatusBar();

        /// <summary>
        /// Clear the status bar message.
        /// </summary>
        public async void ClearStatusBarAsync()
        {
            if (!this._cleanUpStatusBarAutomatically) return;
            await Task.Delay(StatusBarCleanupTimeoutMs);
            TimeSpan delta = DateTime.Now - this.LastStatusBarMessage;
            if (delta.TotalMilliseconds > StatusBarCleanupTimeoutMs) this.ClearStatusBar();
            if (this._cleanUpStatusBarAutomatically) this.ClearStatusBarAsync();
        }

        /// <summary>
        /// Get the corresponding Image.
        /// </summary>
        /// <param name="severity"></param>
        /// <returns></returns>
        public Bitmap SeverityToImage(Severity severity)
        {
            Bitmap image;
            switch (severity)
            {
                case Severity.Info:
                    image = Properties.Resources.Information16x16;
                    break;
                case Severity.Warning:
                    image = Properties.Resources.Warning16x16;
                    break;
                case Severity.Error:
                    image = Properties.Resources.Error16x16;
                    break;
                default:
                    image = null;
                    break;
            }
            return image;
        }

        /// <summary>
        /// Get the corresponding Image.
        /// </summary>
        /// <param name="severity"></param>
        /// <returns></returns>
        public BitmapImage SeverityToBitmapImage(Severity severity)
        {
            Bitmap image = this.SeverityToImage(severity);
            return image == null ? null : image.Bitmap2BitmapImage();
        }
    }
}